﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Admin.NET.Application.DL645
{
    /// <summary>
    /// 电力645协议
    /// </summary>
    public class DL645Agreement
    {
        private string _passwd = "33333333";
        private string _operatorcode = "33333333";

        /// <summary>
        /// 数据解析
        /// </summary>
        /// <param name="infos"></param>
        public static AgreementAnalysis DL645Analysis(Span<byte> infos)
        {
            AgreementAnalysis analysis = new AgreementAnalysis();
            Span<byte> data;
            if (infos[0] == 254)
            {
                int codeIndexInfos = 1;
                data = infos.Slice(1);
                while (infos[codeIndexInfos] == 254)
                {
                    data = data.Slice(1);
                    codeIndexInfos++;
                }
            }
            else
            {
                data = infos;
            }
            if (data.Length < 9)
            {
                new ArgumentException("当前解析参数有误");
            }
            string address = "";

            Span<byte> addressbyte = data.Slice(1, 6);
            foreach (var item in addressbyte)
            {
                address += item.ToString("x2");
            }
            analysis.Address = address;
            string type = data[8].ToString("x2").ToUpper();
            bool suncess = type switch
            {
                "91" => AnalysisRead(analysis, data, AgreementaType.Reading, true),
                "D1" => AnalysisRead(analysis, data, AgreementaType.Reading, false),
                "92" => AnalysisRead(analysis, data, AgreementaType.Reading, true),
                "B2" => AnalysisRead(analysis, data, AgreementaType.ReadAfter, true),
                "D2" => AnalysisRead(analysis, data, AgreementaType.ReadAfter, false),
                "94" => AnalysisRead(analysis, data, AgreementaType.Write, true),
                "D4" => AnalysisRead(analysis, data, AgreementaType.Write, false),
                "93" => AnalysisRead(analysis, data, AgreementaType.ReadAddress, true),
                "95" => AnalysisRead(analysis, data, AgreementaType.WriteAddress, true),
                "96" => AnalysisRead(analysis, data, AgreementaType.Frozen, true),
                "D6" => AnalysisRead(analysis, data, AgreementaType.Frozen, false),
                "97" => AnalysisRead(analysis, data, AgreementaType.CommunicationRate, true),
                "D7" => AnalysisRead(analysis, data, AgreementaType.CommunicationRate, false),
                "98" => AnalysisRead(analysis, data, AgreementaType.UpdatePwd, true),
                "D8" => AnalysisRead(analysis, data, AgreementaType.UpdatePwd, false),
                "99" => AnalysisRead(analysis, data, AgreementaType.MaxClear, true),
                "D9" => AnalysisRead(analysis, data, AgreementaType.MaxClear, false),
                "9A" => AnalysisRead(analysis, data, AgreementaType.Clear, true),
                "DA" => AnalysisRead(analysis, data, AgreementaType.Clear, false),
                "9B" => AnalysisRead(analysis, data, AgreementaType.EventClear, true),
                "DB" => AnalysisRead(analysis, data, AgreementaType.EventClear, false),
                "9C" => AnalysisRead(analysis, data, AgreementaType.SwitchOff, true),
                "DC" => AnalysisRead(analysis, data, AgreementaType.SwitchOff, false),
                "83" => AnalysisRead(analysis, data, AgreementaType.SafetyCertification, true),
                "C3" => AnalysisRead(analysis, data, AgreementaType.SafetyCertification, false),
                _ => false
            };
            return analysis;
        }
        /// <summary>
        /// 读数据无后续数据
        /// </summary>
        /// <param name="analysis"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private static bool AnalysisRead(AgreementAnalysis analysis, Span<byte> data, AgreementaType type, bool sucess)
        {
            int length = data[9];
            Span<byte> info = data.Slice(10, length);//截数据
            string datainfo = "";
            foreach (var item in info)
            {
                datainfo += item.ToString("x2");
            }
            analysis.Data = datainfo;
            analysis.Sucess = sucess;
            analysis.Type = type;
            return true;
        }
        public DL645Agreement() { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="passwd">等级+密码</param>
        /// <param name="operatorcode">操作者代码</param>
        public DL645Agreement(string passwd, string operatorcode)
        {
            _passwd = passwd;
            _operatorcode = operatorcode;
        }
        /// <summary>
        /// 获取发送数据格式
        /// </summary>
        /// <param name="agreementaType"></param>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <param name="value">配合值设置使用</param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public Span<byte> Send645Agreement(AgreementaType agreementaType, string address, string data = null, string value = null)
        {

            Span<byte> agreementa = agreementaType switch
            {
                AgreementaType.Timing => AgreementTiming(address),
                AgreementaType.Reading => AgreementReading(address, data),
                AgreementaType.EventClear => AgreementEventClear(address),
                AgreementaType.Clear => AgreementClear(address),
                AgreementaType.ReadAfter => AgreementReadAfter(address, data),
                AgreementaType.WriteAddress => AgreementWriteAddress(address),
                AgreementaType.CommunicationRate => AgreementCommunicationRate(address, data),
                AgreementaType.Frozen => AgreementFrozen(address, data),
                AgreementaType.Write => AgreementWrite(address, data, value),
                AgreementaType.ReadAddress => AgreementReadAddress(address),
                AgreementaType.MaxClear => AgreementMaxClear(address, data),
                AgreementaType.UpdatePwd => AgreementUpdatePwd(address, data),
                AgreementaType.SwitchOff => AgreementSwitchOff(address, data),
                AgreementaType.SendData => AgreementOther(address, data),
                _ => throw new ArgumentOutOfRangeException(nameof(agreementaType))
            };

            return agreementa;
        }
        /// <summary>
        /// 自定义指令
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private Span<byte> AgreementOther(string address, string data)
        {
            return InitIntegration(address, data, "1C");
        }

        /// <summary>
        /// 拉闸合闸
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data">1是合闸 2拉闸</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementSwitchOff(string address, string data)
        {
            string info = "";
            if (data == "1")
            {
                info = "3435343933333333333333333633";
            }
            else
            {
                info = "3434343933333333333333333533";
            }
            return InitIntegration(address, info, "1C");
        }

        /// <summary>
        /// 修改密码
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementUpdatePwd(string address, string data)
        {
            string info = "33333433" + _passwd + data;
            return InitIntegration(address, info, "18");
        }
        /// <summary>
        /// 最大需量清0
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementMaxClear(string address, string data)
        {
            string info = _passwd + data;
            return InitIntegration(address, info, "19");
        }
        /// <summary>
        /// 读通讯地址
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementReadAddress(string address)
        {

            Span<byte> bytes = new Span<byte>(new byte[16]);
            GetInitFE(bytes);
            string send = "68 AA AA AA AA AA AA 68 13 00 DF 16";
            string[] info = send.Split(' ');

            for (int i = 0; i < info.Length; i++)
            {
                bytes[i + 4] = (byte)Convert.ToInt32(info[i], 16);
            }
            return bytes;
        }
        #region cs
        private int GetCSCode(Span<byte> byteFrame)
        {
            int s = 0;
            for (int k = 0; k < byteFrame.Length; k++)
            {
                s += (byteFrame[k] & 0xff) % 256;
            }
            return s;
        }
        private byte GetSigned(int a)
        {
            if (a > 0x7f)
                return (byte)(a - 256);
            else return (byte)(a);
        }
        #endregion
        /// <summary>
        /// 添加默认FE
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private Span<byte> GetInitFE(Span<byte> bytes)
        {
            for (int i = 0; i < 4; i++)
            {
                bytes[i] = (byte)Convert.ToInt32("FE", 16);
            }
            return bytes;
        }
        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementWrite(string address, string data, string value)
        {

            if (string.IsNullOrEmpty(data))
            {
                throw new ArgumentNullException("data", "当前写数据参数不能为空");
            }
            string info = data + _passwd + _operatorcode + value;
            return InitIntegration(address, info, "14");
        }
        /// <summary>
        /// 冻结
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data">99999999瞬时冻结默认的，99DDhhmm按月冻结</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementFrozen(string address, string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                data = "96969696";
            }
            return InitIntegration(address, data, "16");
        }
        /// <summary>
        /// 更改通讯速率
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementCommunicationRate(string address, string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new ArgumentNullException("data", "当前更改通讯速率参数不能为空");
            }
            return InitIntegration(address, data, "17");
        }
        /// <summary>
        /// 初始化整合操作
        /// </summary>
        /// <returns></returns>
        private Span<byte> InitIntegration(string address, string data, string code)
        {
            Span<byte> bytes = new Span<byte>(new byte[16 + (data.Length / 2)]);
            GetInitFE(bytes);
            SetCodeAndAddress(bytes, address, (data.Length / 2).ToString("x2"), code, data);
            int index = bytes.Length - 2;
            bytes[index] = GetSigned(GetCSCode(bytes.Slice(4)));
            bytes[++index] = (byte)Convert.ToInt32("16", 16);
            return bytes;
        }
        /// <summary>
        /// 写通讯地址
        /// </summary>
        /// <param name="address">dizhi</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementWriteAddress(string address)
        {
            return InitIntegration("AAAAAAAAAAAA", address, "15");
        }

        /// <summary>
        /// 读后续数据 
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private Span<byte> AgreementReadAfter(string address, string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new ArgumentNullException("data", "当前都后续数据参数不能为空");
            }
            //seq前后统一默认05(感觉没必要，后面需要适用都后续数据再改动)

            return InitIntegration(address, data + "38", "12");
        }
        /// <summary>
        /// 电表清零
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementClear(string address)
        {
            string info = _passwd + _operatorcode;
            return InitIntegration(address, info, "1A");
        }
        /// <summary>
        /// 事件清零（默认事件总清0）
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        private Span<byte> AgreementEventClear(string address)
        {
            string info = _passwd + _operatorcode + "32323232";
            return InitIntegration(address, info, "1B");
        }
        /// <summary>
        /// 读取
        /// </summary>
        /// <param name="address"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private Span<byte> AgreementReading(string address, string data)
        {
            //string info = DL645ParameterSet.GetParameterByKey();
            return InitIntegration(address, data, "11");
        }
        /// <summary>
        /// 设置编码和地址
        /// </summary>
        /// <returns></returns>
        private Span<Byte> SetCodeAndAddress(Span<byte> bytes, string address, string length, int code)
        {
            string info = $"68{address}68{code}{length}";
            int index = 0;
            for (int i = 0; i < info.Length; i = i + 2)
            {
                bytes[4 + index] = (byte)Convert.ToInt32(info.Substring(i, 2), 16);
                index++;
            }
            return bytes;
        }
        /// <summary>
        /// 设置编码和地址
        /// </summary>
        /// <returns></returns>
        private Span<Byte> SetCodeAndAddress(Span<byte> bytes, string address, string length, string code, string data)
        {
            string info = $"68{address}68{code}{length}{data}";
            int index = 0;
            for (int i = 0; i < info.Length; i = i + 2)
            {
                bytes[4 + index] = (byte)Convert.ToInt32(info.Substring(i, 2), 16);
                index++;
            }
            return bytes;
        }

        /// <summary>
        /// 广播校验时间
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Span<byte> AgreementTiming(string address)
        {

            return InitIntegration(address, DateTime.Now.ToString("yyyyMMddHHmm"), "08");
        }
    }
    /// <summary>
    /// 通讯类别
    /// </summary>
    public enum AgreementaType
    {
        /// <summary>
        /// 广播校验时间
        /// </summary>
        Timing,
        /// <summary>
        /// 读数据
        /// </summary>
        Reading,
        /// <summary>
        /// 读后续数据
        /// </summary>
        ReadAfter,
        /// <summary>
        /// 读通讯地址
        /// </summary>
        ReadAddress,
        /// <summary>
        /// 写数据
        /// </summary>
        Write,
        /// <summary>
        /// 写通信地址
        /// </summary>
        WriteAddress,
        /// <summary>
        /// 冻结
        /// </summary>
        Frozen,
        /// <summary>
        /// 更改通信速率
        /// </summary>
        CommunicationRate,
        /// <summary>
        /// 修改密码
        /// </summary>
        UpdatePwd,
        /// <summary>
        /// 最大需量清零
        /// </summary>
        MaxClear,
        /// <summary>
        /// 电表清零
        /// </summary>
        Clear,
        /// <summary>
        /// 事件清零
        /// </summary>
        EventClear,
        /// <summary>
        /// 拉闸
        /// </summary>
        SwitchOff,
        /// <summary>
        /// 自定义数据
        /// </summary>
        SendData,
        /// <summary>
        /// 安全认证 永诺系列电编清0
        /// </summary>
        SafetyCertification


    }

    public class AgreementAnalysis
    {
        public string Address { get; set; }
        public AgreementaType Type { get; set; }
        public bool Sucess { get; set; }
        public string Data { get; set; }
    }
}
